package com.wjc.file.controller.admin;


import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.vod.model.v20170321.GetMezzanineInfoResponse;
import com.wjc.server.dto.CommonDto;
import com.wjc.server.dto.FileDto;
import com.wjc.server.enums.FileUseEnum;
import com.wjc.server.service.FileService;
import com.wjc.server.util.Base64ToMultipartFile;
import com.wjc.server.util.SnowFlake;
import com.wjc.server.util.VodUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;

@RestController
@RequestMapping("/admin")
public class UploadController {

    private static final Logger LOG= LoggerFactory.getLogger(UploadController.class);

    @Resource
    private SnowFlake snowFlake;

    @Resource
    private FileService fileService;

    @Value("${file.domain}")
    private String FILE_DOMAIN;

    @Value("${file.path}")
    private String FILE_PATH;

    @Value("${vod.accessKeyId}")
    private String accessKeyId;

    @Value("${vod.accessKeySecret}")
    private String accessKeySecret;



    @PostMapping("/upload")
    public CommonDto upload(@RequestBody FileDto fileDto) throws IOException {
        String use=fileDto.getUse();
        String key =fileDto.getKey();
        String suffix=fileDto.getSuffix();
        String shardBase64=fileDto.getShard();
        MultipartFile shard = Base64ToMultipartFile.base64ToMultipart(shardBase64);

        //保存文件到本地
        FileUseEnum fileUseEnum= FileUseEnum.getByCode(use);
        //获取文件后缀,小写
//        Long key = snowFlake.nextId();
        //如果文件夹不存在则创建
        String dir=fileUseEnum.name().toLowerCase();
        File fullDir=new File(FILE_PATH+dir);
        if(!fullDir.exists()){
            fullDir.mkdir();
        }

        //File.separator,根据操作系统不同生成不同的/或\
//        String path=dir+File.separator+key +"." +suffix;
        //生成分片路径,例如: course/wad2123dfa.mp4.1
        String shardpath= new StringBuffer(dir)
                .append(File.separator)
                .append(key)
                .append(".")
                .append(suffix)
                .append(".")
                .append(fileDto.getShardIndex()).toString();

        //生成文件路径,例如: course/wad2123dfa.mp4,不含".1"
        String filepath= new StringBuffer(dir)
                .append(File.separator)
                .append(key)
                .append(".")
                .append(suffix).toString();

        String fullpath = FILE_PATH+shardpath;
        //生成目标位置
        File dest=new File(fullpath);
        //将file写到目标位置
        shard.transferTo(dest);
        LOG.info(dest.getAbsolutePath());

        //保存文件记录
        LOG.info("保存文件记录开始");
        fileDto.setPath(filepath);
        fileService.save(fileDto);
        CommonDto commonDto = new CommonDto<>();
        fileDto.setPath(FILE_DOMAIN+filepath);
        commonDto.setContent(fileDto);
        return commonDto;
    }

    //合并文件
    @PostMapping("/merge")
     public Boolean merge(@RequestBody FileDto fileDto) throws FileNotFoundException, InterruptedException {
        boolean flag=true;
        LOG.info("合并分片开始");
        String key=fileDto.getKey();
        String suffix=fileDto.getSuffix();
        Integer shardTotal=fileDto.getShardTotal();
        //获取use|course、teacher
        FileUseEnum fileUseEnum= FileUseEnum.getByCode(fileDto.getUse());
        //获取文件后缀,小写
        //将use转为文件夹名|course、teacher
        String dir=fileUseEnum.name().toLowerCase();

        //生成路径,例如: course/wad2123dfa.mp4
        String path= new StringBuffer(dir)
                .append(File.separator)
                .append(key)
                .append(".")
                .append(suffix).toString();

        //生成文件，路径为FILE_PATH+path
        File newFile=new File(FILE_PATH+path);
        FileOutputStream outputStream=new FileOutputStream(newFile,true);
        FileInputStream fileInputStream=null;//分片文件
        byte[] byt=new byte[20*1024*1024];//20MB
        int len;

        try {
            //分片名称后有".1",故1开始循环，
            for(int i=1;i<=shardTotal;i++){
                //读取分片
                fileInputStream =new FileInputStream(FILE_PATH+path+"."+i);
                //读取文件,读到文件末尾返回-1
                while ((len=fileInputStream.read(byt))!=-1){
                    //写文件
                    outputStream.write(byt,0,len);
                }
            }

        } catch (IOException e) {
            LOG.error("合并文件异常",e);
            flag=false;
        }finally {
            try {
                //先判断对象是否为空
                //当io==null时，执行io.close()会发生空指针异常。
                if(fileInputStream!=null){
                    fileInputStream.close();
                }
                outputStream.close();
                LOG.info("IO流关闭");
            } catch (IOException e) {
                LOG.error("IO流关闭",e);
                flag=false;
            }
        }
        LOG.info("合并分片结束");

        //若不进行垃圾回收，文件会一致被占用无法进行删除操作
        //并不会马上进行垃圾回收,所以需要线程休眠100ms等待垃圾回收完成
        System.gc();
        Thread.sleep(100);

        //删除分片
        LOG.info("删除分片开始");
        for (int i = 1; i <= shardTotal ; i++) {
            String delFilePath=FILE_PATH+path+"."+i;
            File file=new File(delFilePath);
            boolean result=file.delete();
            LOG.info("删除{},{}",delFilePath,result ? "成功":"失败");
        }
        LOG.info("删除分片结束");

        return flag;
    }

    //检查分片
    @GetMapping("/check/{key}")
    public CommonDto check(@PathVariable String key) throws Exception {
        LOG.info("检查上传分片开始: {}",key);
        CommonDto commonDto=new CommonDto();
        FileDto fileDto=fileService.findByKey(key);

        //判断数据库是否有值
        if(!ObjectUtils.isEmpty(fileDto)){
            if(StringUtils.isEmpty(fileDto.getVod())){
                fileDto.setPath(FILE_DOMAIN+fileDto.getPath());
            }else {
                LOG.info("数据库中没有vod");
                DefaultAcsClient vodClient = VodUtil.initVodClient(accessKeyId, accessKeySecret);
                GetMezzanineInfoResponse response = VodUtil.getMezzanineInfo(vodClient, fileDto.getVod());
                System.out.println("获取视频信息, response : " + JSON.toJSONString(response));
                String fileUrl = response.getMezzanine().getFileURL();
                fileDto.setPath(fileUrl);
            }
        }

        commonDto.setContent(fileDto);
        return commonDto;
    }



}
